import os
import fitz  # PyMuPDF
import tempfile
from PyPDF2 import PdfReader, PdfWriter
from PIL import Image
import pytesseract
from pdf2image import convert_from_path
import docx
from openpyxl import Workbook
from pptx import Presentation
from pptx.util import Inches, Cm
import pdfplumber
import time
import numpy as np
import cv2
from PyQt5.QtCore import QThread, pyqtSignal
import shutil
import logging
import io
import base64
from PyQt6.QtCore import QObject, pyqtSignal
import httpx
import json

class FileProcessor(QObject):
    progress_updated = pyqtSignal(int)
    conversion_completed = pyqtSignal(str)
    error_occurred = pyqtSignal(str)
    
    def __init__(self):
        super().__init__()
        self.progress_callback = None
        self.temp_dir = os.path.join(tempfile.gettempdir(), "file_converter")
        self.ensure_temp_dir()
        self.api_key = None
        self.client = None
        self.auto_cleanup = True
        self.max_cache_size = 1024 * 1024 * 1000  # 默认1GB
        self.base_url = "https://api.moonshot.cn/v1"  # 初始化 base_url
        self.load_settings()  # 加载设置
        self.init_kimi_client()  # 初始化客户端
        
    def set_progress_callback(self, callback):
        self.progress_callback = callback
        
    def update_progress(self, value):
        if self.progress_callback:
            self.progress_callback(value)
            
    def load_settings(self):
        """加载设置"""
        try:
            # 从配置文件加载设置
            config_path = os.path.join(os.path.expanduser("~"), ".file_converter_config")
            if os.path.exists(config_path):
                with open(config_path, "r", encoding="utf-8") as f:
                    config = json.load(f)
                    if "api_key" in config:
                        self.api_key = config["api_key"]
                        logging.info(f"从配置文件加载API密钥: {self.api_key[:4]}...{self.api_key[-4:]}")
                    if "temp_dir" in config:
                        self.temp_dir = config["temp_dir"]
                    if "auto_cleanup" in config:
                        self.auto_cleanup = config["auto_cleanup"]
                    if "max_cache_size" in config:
                        self.max_cache_size = config["max_cache_size"]
            
            # 如果配置文件中没有API密钥，尝试从环境变量加载
            if not self.api_key:
                self.api_key = os.environ.get("MOONSHOT_API_KEY")
                if self.api_key:
                    logging.info(f"从环境变量加载API密钥: {self.api_key[:4]}...{self.api_key[-4:]}")
                else:
                    logging.warning("未设置 KIMI API 密钥，请在设置中配置")
                        
        except Exception as e:
            logging.error(f"加载设置失败: {str(e)}")
            
    def save_settings(self):
        """保存设置到配置文件"""
        try:
            config = {
                "temp_dir": self.temp_dir,
                "auto_cleanup": self.auto_cleanup,
                "max_cache_size": self.max_cache_size,
                "api_key": self.api_key  # 添加API密钥到配置中
            }
            
            config_path = os.path.join(os.path.expanduser("~"), ".file_converter_config")
            with open(config_path, "w", encoding="utf-8") as f:
                json.dump(config, f, indent=4)
                
            logging.info("设置已保存")
                
        except Exception as e:
            logging.error(f"保存设置失败: {str(e)}")
            
    def check_cache_size(self):
        """检查缓存大小，如果超过限制则清理"""
        try:
            total_size = 0
            for root, dirs, files in os.walk(self.temp_dir):
                for file in files:
                    file_path = os.path.join(root, file)
                    total_size += os.path.getsize(file_path)
                    
            if total_size > self.max_cache_size:
                self.cleanup()
                self.ensure_temp_dir()
                
        except Exception as e:
            logging.error(f"检查缓存大小失败: {str(e)}")
            
    def ensure_temp_dir(self):
        """确保临时目录存在"""
        if not os.path.exists(self.temp_dir):
            os.makedirs(self.temp_dir)
            
    def remove_watermark_pdf(self, input_path, output_path):
        """使用保守的水印去除算法，专注于保持原始文档质量"""
        try:
            # 打开PDF文件
            pdf_document = fitz.open(input_path)
            total_pages = len(pdf_document)
            
            if total_pages == 0:
                raise Exception("PDF文件没有任何页面")
                
            # 创建新的PDF文档
            output_pdf = fitz.open()
            
            for page_num in range(total_pages):
                # 获取页面
                page = pdf_document[page_num]
                
                # 获取页面尺寸
                rect = page.rect
                
                # 创建新页面
                new_page = output_pdf.new_page(width=rect.width, height=rect.height)
                
                # 获取页面内容（使用更高分辨率）
                pix = page.get_pixmap(matrix=fitz.Matrix(3, 3))  # 提高分辨率到3倍
                img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
                
                # 转换为OpenCV格式
                cv_img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
                
                # 1. 保存原始图像
                original = cv_img.copy()
                
                # 2. 转换到灰度图
                gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
                
                # 3. 使用高斯模糊减少噪声
                blurred = cv2.GaussianBlur(gray, (3, 3), 0)
                
                # 4. 使用Canny边缘检测找到文字边缘
                edges = cv2.Canny(blurred, 50, 150)
                
                # 5. 膨胀边缘以保护文字区域
                kernel = np.ones((3,3), np.uint8)
                text_mask = cv2.dilate(edges, kernel, iterations=2)
                
                # 6. 创建水印检测mask
                # 使用自适应阈值检测浅色区域
                light_thresh = cv2.adaptiveThreshold(
                    blurred,
                    255,
                    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                    cv2.THRESH_BINARY,
                    25,
                    5
                )
                
                # 7. 从水印mask中移除文字区域
                watermark_mask = cv2.bitwise_and(light_thresh, cv2.bitwise_not(text_mask))
                
                # 8. 对水印区域进行平滑处理
                smoothed = cv2.GaussianBlur(original, (3,3), 0)
                
                # 9. 创建alpha遮罩用于混合
                alpha = watermark_mask.astype(float) / 255
                alpha = cv2.GaussianBlur(alpha, (3,3), 0)
                alpha = cv2.merge([alpha, alpha, alpha])
                
                # 10. 使用alpha混合原始图像和平滑后的图像
                result = cv2.convertScaleAbs(
                    original * (1.0 - alpha) + smoothed * alpha
                )
                
                # 11. 轻微提高对比度
                result = cv2.convertScaleAbs(result, alpha=1.1, beta=0)
                
                # 转回PIL图像
                cleaned_img = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
                
                # 创建临时文件保存处理后的图像
                with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
                    cleaned_img.save(tmp.name, quality=100)  # 使用最高质量设置
                    # 将处理后的图像插入新页面，使用高质量设置
                    new_page.insert_image(
                        rect,
                        filename=tmp.name,
                        keep_proportion=True,
                        overlay=False
                    )
                    
                # 删除临时文件
                os.unlink(tmp.name)
                
                # 更新进度
                progress = int((page_num + 1) * 100 / total_pages)
                self.update_progress(progress)
                
            # 保存新的PDF，使用高质量设置
            output_pdf.save(
                output_path,
                garbage=4,  # 最高级别的优化
                deflate=True,  # 使用deflate压缩
                clean=True  # 清理冗余数据
            )
            output_pdf.close()
            pdf_document.close()
            
            return output_path
            
        except Exception as e:
            raise Exception(f"PDF去水印失败: {str(e)}")
            
    def pdf_to_image(self, pdf_path, output_path):
        """使用 PyMuPDF 将 PDF 转换为图片"""
        try:
            # 检查输入文件是否存在
            if not os.path.exists(pdf_path):
                raise Exception(f"PDF文件不存在: {pdf_path}")
                
            # 检查输出目录是否可写
            output_dir = os.path.dirname(output_path)
            if not os.path.exists(output_dir):
                try:
                    os.makedirs(output_dir)
                except Exception as e:
                    raise Exception(f"无法创建输出目录: {str(e)}")
                    
            # 打开PDF文件
            try:
                pdf_document = fitz.open(pdf_path)
            except Exception as e:
                raise Exception(f"无法打开PDF文件: {str(e)}")
                
            total_pages = len(pdf_document)
            
            if total_pages == 0:
                pdf_document.close()
                raise Exception("PDF文件没有任何页面")
                
            # 存储所有生成的图片路径
            image_paths = []
            
            # 遍历每一页
            for page_num in range(total_pages):
                try:
                    # 获取页面
                    page = pdf_document[page_num]
                    
                    # 将页面渲染为图片，使用更高的DPI
                    # 使用2倍缩放提高质量
                    zoom = 2.0
                    mat = fitz.Matrix(zoom, zoom)
                    
                    # 获取页面尺寸
                    rect = page.rect
                    
                    # 渲染页面为图片
                    try:
                        pix = page.get_pixmap(matrix=mat, alpha=False)  # 禁用alpha通道，提高兼容性
                    except Exception as e:
                        raise Exception(f"渲染页面失败: {str(e)}")
                    
                    # 构建输出文件路径
                    if total_pages == 1:
                        img_path = output_path
                    else:
                        base_name, ext = os.path.splitext(output_path)
                        img_path = f"{base_name}_{page_num + 1}.png"  # 强制使用 PNG 格式
                    
                    # 确保输出目录存在
                    img_dir = os.path.dirname(img_path)
                    if not os.path.exists(img_dir):
                        os.makedirs(img_dir)
                    
                    # 保存图片，使用PNG格式保证质量
                    try:
                        # 先尝试直接保存
                        pix.save(img_path)
                        
                        # 如果直接保存失败，尝试通过PIL保存
                        if not os.path.exists(img_path) or os.path.getsize(img_path) == 0:
                            img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
                            img.save(img_path, "PNG")
                            img.close()
                            
                    except Exception as e:
                        raise Exception(f"保存图片失败: {str(e)}")
                    
                    # 验证文件是否成功保存
                    if not os.path.exists(img_path):
                        raise Exception(f"无法保存图片: {img_path}")
                        
                    if os.path.getsize(img_path) == 0:
                        raise Exception(f"生成的图片文件为空: {img_path}")
                        
                    # 验证图片是否有效
                    try:
                        with Image.open(img_path) as img:
                            img.verify()
                            # 获取图片信息
                            width, height = img.size
                            if width == 0 or height == 0:
                                raise Exception("图片尺寸无效")
                    except Exception as e:
                        raise Exception(f"生成的图片文件无效: {str(e)}")
                        
                    image_paths.append(img_path)
                    
                    # 更新进度
                    progress = int((page_num + 1) * 100 / total_pages)
                    self.update_progress(progress)
                    
                except Exception as e:
                    # 如果处理单页失败，尝试删除已生成的文件
                    try:
                        if os.path.exists(img_path):
                            os.remove(img_path)
                    except:
                        pass
                    pdf_document.close()
                    raise Exception(f"处理第 {page_num + 1} 页时出错: {str(e)}")
                    
            # 关闭PDF文档
            pdf_document.close()
            
            if not image_paths:
                raise Exception("未能生成任何图片")
                
            # 最终验证所有生成的图片
            valid_paths = []
            for path in image_paths:
                if os.path.exists(path) and os.path.getsize(path) > 0:
                    valid_paths.append(path)
                    
            if not valid_paths:
                raise Exception("所有生成的图片都无效")
                
            return valid_paths[0] if len(valid_paths) == 1 else valid_paths
            
        except Exception as e:
            error_msg = str(e)
            if "permission" in error_msg.lower():
                error_msg = "没有权限访问文件，请检查文件权限"
            elif "file exists" in error_msg.lower():
                error_msg = "目标文件已存在，请选择其他保存位置"
            elif "no such file" in error_msg.lower():
                error_msg = "找不到源文件或无法创建目标目录"
            elif "invalid" in error_msg.lower():
                error_msg = "PDF文件可能已损坏或格式不正确"
            elif "encrypted" in error_msg.lower():
                error_msg = "PDF文件已加密，无法处理"
            elif "memory" in error_msg.lower():
                error_msg = "内存不足，请尝试处理较小的PDF文件"
            raise Exception(f"PDF转图片失败: {error_msg}")
            
    def pdf_to_text(self, pdf_path, output_path):
        """将PDF转换为文本"""
        try:
            # 打开PDF文件
            pdf_document = fitz.open(pdf_path)
            total_pages = len(pdf_document)
            
            if total_pages == 0:
                raise Exception("PDF文件没有任何页面")
                
            # 提取文本
            text_content = []
            for page_num in range(total_pages):
                page = pdf_document[page_num]
                text_content.append(page.get_text())
                
                # 更新进度
                progress = int((page_num + 1) * 100 / total_pages)
                self.update_progress(progress)
                
            # 保存文本文件
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write('\n'.join(text_content))
                
            pdf_document.close()
            return output_path
            
        except Exception as e:
            raise Exception(f"PDF转文本失败: {str(e)}")
            
    def pdf_to_table(self, input_path, output_path):
        with pdfplumber.open(input_path) as pdf:
            total_pages = len(pdf.pages)
            tables = []
            
            for i, page in enumerate(pdf.pages):
                tables.extend(page.extract_tables())
                progress = int((i + 1) / total_pages * 100)
                self.update_progress(progress)
                time.sleep(0.1)  # 模拟处理时间
                
        wb = Workbook()
        ws = wb.active
        for table in tables:
            for row in table:
                ws.append(row)
        wb.save(output_path)
        
    def init_kimi_client(self):
        """初始化KIMI API客户端"""
        try:
            if not self.api_key:
                logging.warning("未设置 KIMI API 密钥，请在设置中配置")
                return
                    
            self.headers = {
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json"
            }
            
            self.client = httpx.Client(
                base_url=self.base_url,
                headers=self.headers
            )
            logging.info("KIMI API 客户端初始化成功")
            
        except Exception as e:
            logging.error(f"初始化 KIMI API 客户端失败: {str(e)}")
            self.client = None
            
    def image_to_text(self, image_path, output_path=None):
        """使用 KIMI API 进行图片文字识别"""
        try:
            if not os.path.exists(image_path):
                raise Exception(f"文件不存在: {image_path}")

            # 确保API客户端已初始化
            self.init_kimi_client()
            if not self.client:
                raise Exception("未设置 KIMI API 密钥，请在设置中配置")

            # 读取图片并转换为base64
            try:
                with open(image_path, "rb") as f:
                    image_data = f.read()
            except Exception as e:
                raise Exception(f"读取图片文件失败: {str(e)}")
                
            try:
                image_url = f"data:image/{os.path.splitext(image_path)[1][1:]};base64,{base64.b64encode(image_data).decode('utf-8')}"
            except Exception as e:
                raise Exception(f"图片编码失败: {str(e)}")
            
            # 调用 KIMI API 进行 OCR 识别，设置较长的超时时间
            try:
                response = self.client.post(
                    "/chat/completions",
                    json={
                        "model": "moonshot-v1-8k-vision-preview",
                        "messages": [
                            {"role": "system", "content": "你是一个专业的 OCR 识别助手，请准确识别图片中的文字内容。"},
                            {
                                "role": "user",
                                "content": [
                                    {
                                        "type": "image_url",
                                        "image_url": {
                                            "url": image_url,
                                        },
                                    },
                                    {
                                        "type": "text",
                                        "text": "请识别图片中的所有文字内容，保持原文格式。",
                                    },
                                ],
                            },
                        ],
                    },
                    timeout=60.0  # 设置60秒超时
                )
            except httpx.TimeoutException:
                raise Exception("API请求超时，请重试")
            except httpx.RequestError as e:
                raise Exception(f"API请求失败: {str(e)}")
            
            if response.status_code != 200:
                raise Exception(f"API 调用失败: {response.text}")
                
            try:
                result = response.json()
                text = result["choices"][0]["message"]["content"]
            except Exception as e:
                raise Exception(f"解析API响应失败: {str(e)}")
            
            # 如果没有提供输出路径，生成一个临时文件路径
            if output_path is None:
                output_path = os.path.join(self.temp_dir, f"ocr_result_{int(time.time())}.txt")
                
            # 保存识别结果
            try:
                with open(output_path, "w", encoding="utf-8") as f:
                    f.write(text)
            except Exception as e:
                raise Exception(f"保存识别结果失败: {str(e)}")
                
            return output_path
            
        except Exception as e:
            logging.error(f"图片文字识别失败: {str(e)}")
            raise Exception(f"图片文字识别失败: {str(e)}")
            
    def word_to_pdf(self, input_path, output_path):
        # TODO: 实现Word转PDF
        for i in range(101):
            self.update_progress(i)
            time.sleep(0.02)  # 模拟处理时间
            
    def excel_to_pdf(self, input_path, output_path):
        # TODO: 实现Excel转PDF
        for i in range(101):
            self.update_progress(i)
            time.sleep(0.02)  # 模拟处理时间
            
    def ppt_to_pdf(self, input_path, output_path):
        # TODO: 实现PPT转PDF
        for i in range(101):
            self.update_progress(i)
            time.sleep(0.02)  # 模拟处理时间
            
    def remove_watermark_image(self, input_path, output_path):
        """去除图片水印，针对白色半透明水印优化"""
        try:
            # 读取图片
            img = cv2.imread(input_path)
            if img is None:
                raise Exception("无法读取图片文件")

            # 转换为RGB格式
            img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            
            # 1. 转换到LAB颜色空间以更好地处理亮度
            lab = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2LAB)
            l, a, b = cv2.split(lab)
            
            # 2. 使用自适应阈值检测潜在的水印区域
            # 增大blockSize和C值以减少误检
            binary = cv2.adaptiveThreshold(
                l,
                255,
                cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                cv2.THRESH_BINARY_INV,
                51,  # 更大的blockSize
                25   # 更大的C值
            )
            
            # 3. 使用形态学操作清理噪点
            kernel = np.ones((3,3), np.uint8)
            binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
            
            # 4. 连通区域分析，移除太大或太小的区域
            num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary, connectivity=8)
            
            # 计算合理的水印大小范围
            img_area = img.shape[0] * img.shape[1]
            min_size = img_area * 0.001  # 最小水印面积
            max_size = img_area * 0.1    # 最大水印面积
            
            # 创建掩码，只保留合适大小的区域
            mask = np.zeros_like(binary)
            for i in range(1, num_labels):  # 从1开始，跳过背景
                if min_size < stats[i, cv2.CC_STAT_AREA] < max_size:
                    # 获取当前连通区域
                    component_mask = (labels == i).astype(np.uint8) * 255
                    mask = cv2.bitwise_or(mask, component_mask)
            
            # 5. 扩展水印区域边缘以确保完全覆盖
            mask = cv2.dilate(mask, kernel, iterations=2)
            
            # 6. 使用Inpainting修复水印区域
            # 首先使用TELEA方法
            result = cv2.inpaint(img_rgb, mask, 3, cv2.INPAINT_TELEA)
            # 然后使用NS方法进行补充修复
            result = cv2.inpaint(result, mask, 5, cv2.INPAINT_NS)
            
            # 7. 保持原始图像中未检测到水印的区域不变
            mask_inv = cv2.bitwise_not(mask)
            original_part = cv2.bitwise_and(img_rgb, img_rgb, mask=mask_inv)
            inpainted_part = cv2.bitwise_and(result, result, mask=mask)
            result = cv2.add(original_part, inpainted_part)
            
            # 8. 轻微调整对比度和亮度以匹配原图风格
            result = cv2.convertScaleAbs(result, alpha=1.05, beta=-5)
            
            # 9. 保存结果
            result_bgr = cv2.cvtColor(result, cv2.COLOR_RGB2BGR)
            cv2.imwrite(output_path, result_bgr, [cv2.IMWRITE_PNG_COMPRESSION, 0])
            
            # 验证文件是否成功保存
            if not os.path.exists(output_path):
                raise Exception("无法保存处理后的图片")
                
            return output_path
            
        except Exception as e:
            raise Exception(f"图片去水印失败: {str(e)}")
            
    def pdf_to_ppt(self, input_path, output_path):
        """将PDF转换为PPT"""
        try:
            # 创建新的PPT演示文稿
            prs = Presentation()
            
            # 设置默认幻灯片尺寸为16:9
            prs.slide_width = Inches(16)
            prs.slide_height = Inches(9)
            
            # 打开PDF文件
            pdf_document = fitz.open(input_path)
            total_pages = len(pdf_document)
            
            if total_pages == 0:
                raise Exception("PDF文件没有任何页面")
                
            # 创建临时目录用于存储图片
            with tempfile.TemporaryDirectory() as temp_dir:
                # 遍历每一页PDF
                for page_num in range(total_pages):
                    # 获取PDF页面
                    page = pdf_document[page_num]
                    
                    # 将页面转换为图片（使用更高的DPI以获得更好的质量）
                    pix = page.get_pixmap(matrix=fitz.Matrix(3, 3))  # 3x缩放以获得更好的质量
                    
                    # 保存为临时图片文件
                    temp_image_path = os.path.join(temp_dir, f"page_{page_num + 1}.png")
                    pix.save(temp_image_path)
                    
                    # 创建新的幻灯片（使用空白布局）
                    slide_layout = prs.slide_layouts[6]  # 6 代表空白布局
                    slide = prs.slides.add_slide(slide_layout)
                    
                    # 获取幻灯片尺寸
                    slide_width = prs.slide_width
                    slide_height = prs.slide_height
                    
                    # 添加图片到幻灯片并保持纵横比
                    img = Image.open(temp_image_path)
                    width, height = img.size
                    img.close()
                    
                    # 计算适当的图片尺寸以保持纵横比
                    ratio = min(slide_width / width, slide_height / height)
                    new_width = width * ratio
                    new_height = height * ratio
                    
                    # 计算居中位置
                    left = (slide_width - new_width) / 2
                    top = (slide_height - new_height) / 2
                    
                    # 添加图片到幻灯片
                    slide.shapes.add_picture(
                        temp_image_path,
                        left, top,
                        width=new_width,
                        height=new_height
                    )
                    
                    # 更新进度
                    progress = int((page_num + 1) * 100 / total_pages)
                    self.update_progress(progress)
                    
            # 保存PPT文件
            prs.save(output_path)
            
            # 验证文件是否成功保存
            if not os.path.exists(output_path):
                raise Exception("无法保存PPT文件")
                
            return output_path
            
        except Exception as e:
            raise Exception(f"PDF转PPT失败: {str(e)}")
            
    def pdf_to_word(self, input_path, output_path):
        """将PDF转换为Word文档"""
        try:
            # 创建一个新的Word文档
            doc = docx.Document()
            
            # 打开PDF文件
            pdf_document = fitz.open(input_path)
            total_pages = len(pdf_document)
            
            if total_pages == 0:
                raise Exception("PDF文件没有任何页面")
                
            # 创建临时目录用于存储图片
            with tempfile.TemporaryDirectory() as temp_dir:
                # 遍历每一页PDF
                for page_num in range(total_pages):
                    # 获取PDF页面
                    page = pdf_document[page_num]
                    
                    # 添加页面分隔符（除了第一页）
                    if page_num > 0:
                        doc.add_page_break()
                    
                    # 提取文本块
                    blocks = page.get_text("blocks")
                    
                    # 按垂直位置排序文本块
                    blocks.sort(key=lambda b: (b[1], b[0]))  # 按y坐标，然后是x坐标排序
                    
                    # 处理每个文本块
                    for block in blocks:
                        text = block[4]
                        if text.strip():
                            # 创建段落
                            p = doc.add_paragraph()
                            # 添加文本
                            run = p.add_run(text)
                            # 设置基本格式
                            run.font.size = docx.shared.Pt(11)  # 11pt 字体
                            run.font.name = 'SimSun'  # 宋体
                            
                    # 处理图片
                    image_list = page.get_images(full=True)
                    if image_list:
                        for img_index, img_info in enumerate(image_list):
                            try:
                                # 获取图片
                                xref = img_info[0]
                                base_image = pdf_document.extract_image(xref)
                                image_bytes = base_image["image"]
                                
                                # 保存为临时图片文件
                                temp_image_path = os.path.join(temp_dir, f"image_{page_num}_{img_index}.png")
                                with open(temp_image_path, "wb") as temp_file:
                                    temp_file.write(image_bytes)
                                
                                # 添加图片到文档，并设置合适的大小
                                width = base_image.get("width", 500)
                                height = base_image.get("height", 400)
                                
                                # 计算适当的图片大小（最大宽度为页面宽度的80%）
                                max_width = docx.shared.Inches(6)  # 约为A4纸宽度的80%
                                if width > max_width:
                                    ratio = max_width / width
                                    width = max_width
                                    height = height * ratio
                                
                                # 添加图片
                                doc.add_picture(temp_image_path, width=docx.shared.Inches(width/96))
                                
                            except Exception as img_error:
                                print(f"处理图片时出错: {str(img_error)}")
                                continue
                    
                    # 更新进度
                    progress = int((page_num + 1) * 100 / total_pages)
                    self.update_progress(progress)
                
                try:
                    # 保存Word文档
                    doc.save(output_path)
                    
                    # 验证文件是否成功保存
                    if not os.path.exists(output_path):
                        raise Exception("无法保存Word文件")
                        
                except Exception as save_error:
                    raise Exception(f"保存Word文档失败: {str(save_error)}")
                
                return output_path
                
        except Exception as e:
            raise Exception(f"PDF转Word失败: {str(e)}")
            
    def image_to_pdf(self, input_path, output_path):
        """将图片转换为PDF"""
        try:
            # 检查输入文件是否存在
            if not os.path.exists(input_path):
                raise Exception(f"图片文件不存在: {input_path}")
                
            # 检查输出目录是否可写
            output_dir = os.path.dirname(output_path)
            if not os.path.exists(output_dir):
                try:
                    os.makedirs(output_dir)
                except Exception as e:
                    raise Exception(f"无法创建输出目录: {str(e)}")
            
            # 打开图片文件
            try:
                image = Image.open(input_path)
                # 转换为RGB模式（如果是RGBA，去除alpha通道）
                if image.mode in ('RGBA', 'LA'):
                    background = Image.new('RGB', image.size, (255, 255, 255))
                    if image.mode == 'RGBA':
                        background.paste(image, mask=image.split()[3])
                    else:
                        background.paste(image, mask=image.split()[1])
                    image = background
                elif image.mode != 'RGB':
                    image = image.convert('RGB')
                
                # 创建PDF文档
                pdf_document = fitz.open()
                
                # 获取图片尺寸
                width, height = image.size
                
                # 创建新页面
                pdf_page = pdf_document.new_page(width=width, height=height)
                
                # 将图片保存为临时文件
                with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
                    image.save(tmp.name, 'PNG', quality=100)
                    
                    # 将图片插入PDF页面
                    rect = fitz.Rect(0, 0, width, height)
                    pdf_page.insert_image(rect, filename=tmp.name)
                    
                    # 删除临时文件
                    os.unlink(tmp.name)
                
                # 保存PDF文件
                pdf_document.save(
                    output_path,
                    garbage=4,  # 最高级别的优化
                    deflate=True,  # 使用deflate压缩
                    clean=True  # 清理冗余数据
                )
                pdf_document.close()
                
                # 验证文件是否成功保存
                if not os.path.exists(output_path):
                    raise Exception("无法保存PDF文件")
                    
                # 更新进度
                self.update_progress(100)
                
                return output_path
                
            except Exception as e:
                raise Exception(f"处理图片文件失败: {str(e)}")
                
        except Exception as e:
            error_msg = str(e)
            if "permission" in error_msg.lower():
                error_msg = "没有权限访问文件，请检查文件权限"
            elif "format" in error_msg.lower():
                error_msg = "不支持的图片格式或图片文件已损坏"
            elif "memory" in error_msg.lower():
                error_msg = "内存不足，请尝试处理较小的图片文件"
            raise Exception(f"图片转PDF失败: {error_msg}")
            
    def cleanup(self):
        """清理临时文件"""
        try:
            if os.path.exists(self.temp_dir):
                shutil.rmtree(self.temp_dir)
        except Exception as e:
            logging.error(f"清理临时文件失败: {str(e)}")
            
    def set_api_key(self, api_key):
        """设置API密钥并初始化客户端"""
        self.api_key = api_key
        self.save_settings()  # 保存设置
        self.init_kimi_client()  # 重新初始化客户端 